"""
CsmthStation相关配置文件解析类
@file   csm_config_parser.py
@author tgl233
@date   2019-10-30
"""

import configparser
import re
import os
import logging
from random import randint
from docxtpl import DocxTemplate
from configparser import ConfigParser

__logger = logging.getLogger(__name__)


# __logger.addHandler(logging.NullHandler())


class AnalogParser(object):
    # 模拟量配置项中每列的含义如下：
    # 名称，标示，AD序号，显示序号，最小值，最大值，系数，报警上限，报警下限，分路上限，分机号
    _analog_column_implication = r"""
    name            # 名称
    flag            # 标志
    AD_number       # AD序号
    view_number     # 显示序号
    minimal         # 最小值
    maximal         # 最大值
    coefficient     # 系数
    alarm_maximal   # 报警上限
    alarm_minimal   # 报警下限
    occupy          # 分路上限
    gather_number   # 分机号
    """
    # 将_analog_column_implication转为小写，再去除注释内容后再产生列表
    __analog_implication_lower_list = re.sub(r'(#.*\n)|(#.*$)', '', _analog_column_implication.lower()).split()

    #  _regular_analog_str = r"""
    # (?:(?P<analog_ini>.*?),){10,10}       # 匹配配置前10个以","结尾的配置内容
    # .*?(?P<gather_number>\d+\D)           # 匹配最后的分机号
    # """
    # __regular_analog = re.compile(_regular_analog_str,re.VERBOSE)

    def __init__(self, ):
        self.__data = {}

    @property
    def data(self) -> dict:
        return self.__data

    def clear(self) -> None:
        self.__data.clear()

    def parser(self, filename, encoding=None, comment_prefixes=('//', '#', ';')) -> dict:
        cfg = ConfigParser(comment_prefixes=comment_prefixes, inline_comment_prefixes=comment_prefixes)
        cfg.read(filename, encoding)
        try:
            # 先从配置文件中的“模拟量项目”中取出子项数目数量来
            for sub_section in range(cfg.getint('模拟量项目', '子项数目')):
                # 再从子项中取数“名称”和“总路数”
                sub_section_name = '子项{0}'.format(sub_section + 1)
                name = cfg.get(sub_section_name, '名称')
                total = cfg.getint(sub_section_name, '总路数')
                # 再从子项中取出每一项配置进行解析
                sub_section_list = []
                for item in range(total):
                    context = cfg.get(sub_section_name, str(item + 1), raw=True)
                    if context.startswith('DUMMY'):
                        continue
                    # 将每项配置转化为列表,并去除空白字符
                    context_list = [item.strip() for item in context.split(',')]
                    sub_section_list.append(dict(zip(self.__analog_implication_lower_list, context_list)))
                if len(sub_section_list) != 0:
                    self.__data[name] = sub_section_list
        except configparser.NoSectionError as e:
            print("{0}不是模拟量配置文件,{1}".format(os.path.normpath(filename), e))
        finally:
            return self.data


class DigitParser(object):
    # 开关量系列含义：
    # 名称，AD序号，标志，取反，分机
    _Digit_column_implication = r"""
    name            # 名称
    AD_number       # AD序号
    flag            # 标志
    reversal        # 取反
    gather_number   # 分机号
    """
    __dight_implication_lower_list = re.sub(r'(#.*\n)|(#.*$)', '', _Digit_column_implication.lower()).split()

    def __init__(self):
        self.__data = {}

    @property
    def data(self):
        return self.__data

    def parser(self, filename, allowed_gather_number='0 9 21', encoding=None,
               comment_prefixes=('//', '#', ';')) -> dict:
        cfg = configparser.ConfigParser(comment_prefixes=comment_prefixes, inline_comment_prefixes=comment_prefixes)
        cfg.read(filename, encoding)
        try:
            for option, item in cfg.items('开关量'):
                if option == '总路数':
                    continue
                else:
                    context_list = [i.strip() for i in item.split(',')]
                    context = dict(zip(self.__dight_implication_lower_list, context_list))
                    if context['name'] == 'DUMMY':
                        continue
                    if context.get('gather_number') in allowed_gather_number:
                        if context.get('gather_number') in self.__data:
                            self.__data[context['gather_number']].append(
                                dict(name=context['name'], flag=context['flag']))
                        else:
                            self.__data.update(
                                {context['gather_number']: [dict(name=context['name'], flag=context['flag'])]})
        except configparser.NoSectionError as e:
            print("{0}不是开关量配置文件,{1}".format(os.path.normpath(filename), e))
        finally:
            return self.data


def format_page(record: list, first: int, middle: int, end: int, one_page: int):
    if len(record) <= one_page:
        count = one_page - len(record)
        while count != 0:
            count -= 1
            record.append({})
    elif len(record) <= first + end:
        count = first + end - len(record)
        while count != 0:
            count -= 1
            record.append({})
    else:
        count = middle - (len(record) - first - end) % middle
        while count != 0:
            count -= 1
            record.append({})


def generate_insulation(record: dict) -> dict:
    insulation_dict = {}
    insulation_list = []
    if '电缆绝缘' in record:
        insulation_dict['has_insulation'] = True
        for number, item in enumerate(record['电缆绝缘'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            if '1M校核' in new_item['name']:
                value = round(randint(95, 109) / 100, 2)
                voltage = randint(475, 490)
            elif '2M校核' in new_item['name']:
                value = round(randint(195, 208) / 100, 2)
                voltage = randint(475, 490)
            elif '5M校核' in new_item['name']:
                value = round(randint(493, 510) / 100, 2)
                voltage = randint(475, 490)
            else:
                value = round(randint(900, 1000) / 100, 2)
                voltage = randint(495, 505)
            new_item.update(dict(value=value, voltage=voltage))
            insulation_list.append(new_item)

        # 格式化输出文档
        # count = len(insulation_list)
        # if count <= 37:  # 1页最多37行
        #     i = 37 - count
        #     while i != 0:
        #         i -= 1
        #         insulation_list.append({})
        # elif count <= (39 + 39):  # 两页的话每页都为39行
        #     i = 39 + 39 - count
        #     while i != 0:
        #         i -= 1
        #         insulation_list.append({})
        # else:  # 大于两页中间每页为41行
        #     i = 41 - (count - 39 - 39) % 41
        #     while i != 0:
        #         i -= 1
        #         insulation_list.append({})

        # format_page(insulation_list,39,41,39,37)
        insulation_dict['insulation'] = insulation_list
    else:
        insulation_dict['has_insulation'] = False
    return insulation_dict


def generate_leakage(record: dict) -> dict:
    leakage_dict = {}
    leakage_list = []
    if '电源漏流' in record:
        leakage_dict['has_leakage'] = True
        for number, item in enumerate(record['电源漏流'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            if '-Z' in new_item['name'] or '-F' in new_item['name']:
                value = round(randint(0, 10) / 100, 2)
            else:
                value = round(randint(1, 1000) / 100, 2)
            actual = round(value * float(new_item['coefficient']), 2)
            new_item.update(dict(value=value, actual=actual))
            leakage_list.append(new_item)

        # 格式化输出文档
        # count = len(leakage_list)
        # if count <= 35:  # 1页最多35行
        #     i = 37 - count
        #     while i != 0:
        #         i -= 1
        #         leakage_list.append({})
        # elif count <= (36 + 37):  # 两页的话第1页为36行，第2页为37
        #     i = 36 + 37 - count
        #     while i != 0:
        #         i -= 1
        #         leakage_list.append({})
        # else:  # 大于两页中间每页为38行
        #     i = 38 - (count - 36 - 37) % 38
        #     while i != 0:
        #         i -= 1
        #         leakage_list.append({})

        # format_page(leakage_list,36,38,37,35)
        leakage_dict['leakage'] = leakage_list
    else:
        leakage_dict['has_leakage'] = False
    return leakage_dict


def generate_voltage_phase(record: dict) -> dict:
    voltage_phase_dict = {}
    voltage_phase_list = []
    if '轨道相位角' in record:
        voltage_phase_dict['has_voltage_phase'] = True
        for number, item in enumerate(record['轨道相位角'], start=1):
            new_item = {'number': number, 'name': item['name'].replace('轨道相位角',''), 'coefficient': item['coefficient']}
            value_voltage = round(randint(2000, 2400) / 100, 2)
            actual_voltage = round(value_voltage * float(new_item['coefficient']), 2)
            value_phase = round(randint(9000, 10000) / 100, 2)
            actual_phase = round(value_phase * float(new_item['coefficient']), 2)
            new_item.update(dict(value_voltage=value_voltage, value_phase=value_phase,
                                 actual_voltage=actual_voltage, actual_phase=actual_phase))
            voltage_phase_list.append(new_item)
            voltage_phase_dict['voltage_phase'] = voltage_phase_list
    else:
        voltage_phase_dict['has_voltage_phase'] = False
    return voltage_phase_dict


def generate_turnout_voltage(record: dict) -> dict:
    turnout_voltage_dict = {}
    turnout_voltage_list = []
    if '道岔表示电压' in record:
        turnout_voltage_dict['has_turnout_voltage'] = True
        for number, item in enumerate(record['道岔表示电压'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            if '交流' in new_item['name']:
                value = round(randint(5500, 6500) / 100, 2)
            else:
                value = round(randint(2000, 2500) / 100, 2)
            actual_value = round(value * float(new_item['coefficient']), 2)
            new_item.update(dict(value=value, actual=actual_value))
            turnout_voltage_list.append(new_item)
        turnout_voltage_dict['turnout_voltage'] = turnout_voltage_list
    else:
        turnout_voltage_dict['has_turnout_voltage'] = False
    return turnout_voltage_dict


def generate_lamp_current(record: dict) -> dict:
    lamp_current_dict = {}
    lamp_current_list = []
    if '灯丝继电器电流' in record:
        lamp_current_dict['has_lamp_current'] = True
        for number, item in enumerate(record['灯丝继电器电流'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            value = round(randint(12000, 15000) / 100, 2)
            actual_value = round(value * float(new_item['coefficient']), 2)
            new_item.update(dict(value=value, actual=actual_value))
            lamp_current_list.append(new_item)
        lamp_current_dict['lamp_current'] = lamp_current_list
    else:
        lamp_current_dict['has_lamp_current'] = False
    return lamp_current_dict


def generate_joint_voltage(record: dict) -> dict:
    joint_voltage_dict = {}
    joint_voltage_list = []
    if '站联电压' in record:
        joint_voltage_dict['has_joint_voltage'] = True
        for number, item in enumerate(record['站联电压'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            if '电流' in new_item['name']:
                continue
            value = round(randint(2000, 3600) / 100, 2)
            actual_value = round(value * float(new_item['coefficient']), 2)
            new_item.update(dict(value=value, actual=actual_value))
            joint_voltage_list.append(new_item)
        joint_voltage_dict['joint_voltage'] = joint_voltage_list
    else:
        joint_voltage_dict['has_joint_voltage'] = False
    return joint_voltage_dict


def generate_wdw_voltage(record: dict) -> dict:
    wdw_voltage_dict = {}
    wdw_voltage_list = []
    if '外电网' in record:
        wdw_voltage_dict['has_wdw_voltage'] = True
        for number, item in enumerate(record['外电网'], start=1):
            new_item = {'number': number, 'name': item['name'], 'coefficient': item['coefficient']}
            if '频率' in new_item['name']:
                value = 50.00
                actual_value = round(value * float(new_item['coefficient']),2)
                new_item.update(dict(value=value, actual=actual_value))
                wdw_voltage_list.append(new_item)
                continue
            elif '相电压' in new_item['name'] and '夹角' not in new_item['name']:
                value = 230 - round(randint(0, 1000) / 100, 2)
                actual_value = round(value * float(new_item['coefficient']),2)
                new_item.update(dict(value=value, actual=actual_value))
                wdw_voltage_list.append(new_item)
                continue
            elif '线电压' in new_item['name']:
                value = 400 - round(randint(0, 1000) / 100, 2)
                actual_value = round(value * float(new_item['coefficient']),2)
                new_item.update(dict(value=value, actual=actual_value))
                wdw_voltage_list.append(new_item)
                continue
            elif '电压夹角' in new_item['name']:
                value = 120
                actual_value = round(value * float(new_item['coefficient']),2)
                new_item.update(dict(value=value, actual=actual_value))
                wdw_voltage_list.append(new_item)
                continue
        wdw_voltage_dict['wdw_voltage'] = wdw_voltage_list
    else:
        wdw_voltage_dict['has_wdw_voltage'] = False
    return wdw_voltage_dict


def generate_turnout_curve(record: dict) -> dict:
    turnout_curve_dict = {}
    turnout_curve_list = []
    if '道岔动作曲线' in record:
        turnout_curve_dict['has_turnout_curve'] = True
        for number, item in enumerate(record['道岔动作曲线'], start=1):
            new_item = {'number': number, 'name': item['name']}
            turnout_curve_list.append(new_item)
        turnout_curve_dict['turnout_curve'] = turnout_curve_list
    else:
        turnout_curve_dict['has_turnout_curve'] = False
    return turnout_curve_dict


def generate_fuse_digit(record: dict) -> dict:
    fuse_digit_dict = {}
    fuse_digit_list = []
    for key, list_item in record.items():
        for item in list_item:
            if item['flag'] == '17':
                new_item = {'number': len(fuse_digit_list) + 1, 'name': item['name']}
                fuse_digit_list.append(new_item)
    if len(fuse_digit_list) != 0:
        fuse_digit_dict['has_fuse_digit'] = True
        fuse_digit_dict['fuse_digit'] = fuse_digit_list
    else:
        fuse_digit_dict['has_fuse_digit'] = False

    return fuse_digit_dict


def generate_turnout_digit(record: dict) -> dict:
    turnout_digit_dict = {}
    turnout_digit_list = []
    for key, list_item in record.items():
        for item in list_item:
            if item['flag'] in '9 8 88'.split():
                new_item = {'number': len(turnout_digit_list) + 1, 'name': item['name']}
                turnout_digit_list.append(new_item)
    if len(turnout_digit_list) != 0:
        turnout_digit_dict['has_turnout_digit'] = True
        turnout_digit_dict['turnout_digit'] = turnout_digit_list
    else:
        turnout_digit_dict['has_turnout_digit'] = False

    return turnout_digit_dict


def generate_other_digit(record: dict) -> dict:
    other_digit_dict = {}
    other_digit_list = []
    for key, list_item in record.items():
        for item in list_item:
            if item['flag'] == '128':
                new_item = {'number': len(other_digit_list) + 1, 'name': item['name']}
                other_digit_list.append(new_item)
    if len(other_digit_list) != 0:
        other_digit_dict['has_other_digit'] = True
        other_digit_dict['other_digit'] = other_digit_list
    else:
        other_digit_dict['has_other_digit'] = False

    return other_digit_dict


def auto_generate(config_directory, station, recorder, date, out_path, allowed_analog="""
    道岔动作曲线
    道岔表示电压
    灯丝继电器电流
    站联电压
    电缆绝缘
    电源漏流
    外电网
    轨道相位角
    # 电源屏
"""):

    if os.path.exists(config_directory) and os.path.isdir(config_directory):
        __logger.info('开始解析"%s"目录下的模拟量数据...',config_directory)
        context = {}
        filter_list = re.sub(r'(#.*\n)|(#.*$)', '', allowed_analog).split()
        error_count = 0
        analog = AnalogParser()
        for item in "zh.ini jc.ini gd.ini dc.ini".split():
            if os.path.exists(os.path.join(config_directory, item)):
                __logger.info("解析配置文件:{0}".format(item))
                analog.parser(os.path.join(config_directory, item))
            else:
                __logger.warning('配置文件:"{0}"不存在！'.format(os.path.join(config_directory, item)))
                error_count += 1
        temp_list = {k: v for k, v in analog.data.items() if k in filter_list}
        context.update(generate_turnout_curve(temp_list))
        context.update(generate_wdw_voltage(temp_list))
        context.update(generate_joint_voltage(temp_list))
        context.update(generate_lamp_current(temp_list))
        context.update(generate_turnout_voltage(temp_list))
        context.update(generate_voltage_phase(temp_list))
        context.update(generate_leakage(temp_list))
        context.update(generate_insulation(temp_list))

        __logger.info('开始解析"%s"目录下的开关量数据...', config_directory)
        digit = DigitParser()
        if os.path.exists(os.path.join(config_directory, 'digit.ini')):
            __logger.info("解析开配置文件:digit.ini")
            digit.parser(os.path.join(config_directory, 'digit.ini'))
            context.update(digit.data)
        else:
            __logger.error('配置文件:"{0}"不存在！'.format(os.path.join(config_directory, 'digit.ini')))
            error_count += 1

        context.update(generate_fuse_digit(digit.data))
        context.update(generate_turnout_digit(digit.data))
        context.update(generate_other_digit(digit.data))

        context.update(dict(station=station, recorder=recorder, date=date))

        if error_count == 5:
            return None

        if 'voltage_phase' in context:
            tpl = DocxTemplate('./template/template-25Hz.docx')
        else:
            tpl = DocxTemplate('./template/template.docx')
        tpl.render(context)
        tpl.save(os.path.join(out_path, "微机监测系统现场调试数据记录表(JL-8.5-04)——{0}.docx".format(station)))
        __logger.info('成功生成：微机监测系统现场调试数据记录表(JL-8.5-04)——%s',station)
        return os.path.normpath(os.path.join(out_path, "微机监测系统现场调试数据记录表(JL-8.5-04)——{0}.docx".format(station)))
    else:
        if os.path.isdir(config_directory):
            __logger.error('配置文件目录:"%s"不存在！', config_directory)
        else:
            __logger.error('"{0}"不是配置文件目录'.format(config_directory))
        return None


if __name__ == '__main__':
    # import wx
    # import os
    # import pprint
    # from random import randint
    # from docxtpl import DocxTemplate
    #
    # record_item_str = re.sub(r'(#.*\n)|(#.*$)', '', """
    # 道岔动作曲线
    # 道岔表示电压
    # 灯丝继电器电流
    # 站联电压
    # 电缆绝缘
    # 电源漏流
    # 外电网
    # 轨道相位角
    # # 电源屏
    # """)
    #
    # analog_test = AnalogParser()
    # digit_test = DigitParser()
    # app = wx.App()
    # app.MainLoop()
    # dlg = wx.FileDialog(None, '请选择要解析的站机配置文件', wildcard='*.ini', style=wx.FD_MULTIPLE)
    # dlg.ShowModal()
    #
    # try:
    #     for f in dlg.GetFilenames():
    #         file = os.path.join(os.path.dirname(dlg.GetPath()), f)
    #         analog_test.parser(file)
    #         digit_test.parser(file)
    #
    #     # analog.parser(dlg.GetPath())
    # finally:
    #     pprint.pprint(analog_test.data.keys())
    #     pprint.pprint(digit_test.data.keys())
    #
    # record_data = {k: v for k, v in analog_test.data.items() if k in record_item_str.split()}
    #
    # context_value = generate_insulation(record_data)
    # # context = generate_leakage(record_data)
    # context_value.update(generate_leakage(record_data))
    # # print(generate_voltage_phase(record_data))
    # context_value.update(generate_voltage_phase(record_data))
    # # print(generate_turnout_voltage(record_data))
    # context_value.update(generate_turnout_voltage(record_data))
    # # print(generate_lamp_current(record_data))
    # context_value.update(generate_lamp_current(record_data))
    # # print(generate_joint_voltage(record_data))
    # context_value.update(generate_joint_voltage(record_data))
    # # print(generate_wdw_voltage(record_data))
    # context_value.update(generate_wdw_voltage(record_data))
    # # print(generate_turnout_curve(record_data))
    # context_value.update(generate_turnout_curve(record_data))
    # # print(generate_fuse_digit(digit.data))
    # context_value.update(generate_fuse_digit(digit.data))
    # # print(generate_turnout_digit(digit.data))
    # context_value.update(generate_turnout_digit(digit.data))
    # print(generate_other_digit(digit.data))
    # context_value.update((generate_other_digit(digit.data)))
    # # pprint.pprint(context)
    #
    # tpl = DocxTemplate(r'template.docx')
    # tpl.render(context_value)
    # tpl.save('test.docx')

    import wx

    log = logging.getLogger(__name__)
    log.addHandler(logging.StreamHandler())
    log.setLevel(logging.DEBUG)
    app = wx.App()
    directory_dlg = wx.DirDialog(None, "请选择配置文件目录", defaultPath='.')
    app.MainLoop()
    directory_dlg.ShowModal()

    auto_generate(directory_dlg.GetPath(), "Test", 'TGL', '2019-11-22', '.')
